﻿using AutoMapper;
using IdentityModel;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.IdentityModel.Tokens;
using Rabc.Project.Repositories;
using Rbac.Domain;
using Rbac.Project.Application.Admins.Dto;
using Rbac.Project.Utility;
using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Net.Http;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;

namespace Rbac.Project.Application.Admins
{
    public class AdminService : IAdminService
    {
        private readonly IRepository<Admin> repository;
        private readonly IRepository<AdminRole> repository1;
        private readonly IMapper mapper;
        private readonly IConfiguration configuration;

        public AdminService(
            IRepository<Admin> repository,
            IRepository<AdminRole> repository1,
            IMapper mapper, 
            IConfiguration configuration
            )
        {
            this.repository = repository;
            this.repository1 = repository1;
            this.mapper = mapper;
            this.configuration = configuration;
        }

        public async Task<ResultDto<Admin>> InsertAsync(CreateOrUpdateDto dto)
        {
            try
            {
                if (await repository.ExistsAsync(m => m.UserName == dto.UserName))
                {
                    return new ResultDto<Admin> { Code = Result.Success, Message = "用户已存在" };
                }
                else
                {
                    dto.Password = dto.Password.Md5();

                    var admin = mapper.Map<CreateOrUpdateDto, Admin>(dto);

                    await repository.InsertAsync(admin);

                    return new ResultDto<Admin> { Code = Result.Success };
                }
            }
            catch (Exception e)
            {
                return new ResultDto<Admin> { Code = Result.Failure, Message = e.Message };
            }
        }

        public async Task<LoginResultDto> LoginAsync(LoginDto dto)
        {
            var admin = await repository.FindAsync(m=>m.UserName == dto.UserName);
            if(admin == null)
            {
                return new LoginResultDto { Code = Result.Success, Info = LoginInfo.NoneUser, Message = "无此用户" };
            }
            else
            {
                if(admin.Password.ToUpper() == dto.Password.Md5().ToUpper())
                {
                    //生成Token
                    //更新末次登录IP和末次登录时间
                    /*admin.LastLoginIP = httpContext.HttpContext.Connection.RemoteIpAddress.MapToIPv4().ToString();
                    admin.LastLoginTime = DateTime.Now;
                    adminRepository.Update(admin);*/

                    var roleIds = repository1.Queryable().Where(m => m.AdminId == admin.AdminId).Select(m=>m.RoleID).ToList();

                    //身份信息认证
                    //写Session或Cookies换成JWT
                    IList<Claim> claims = new List<Claim> {
                        new Claim(JwtClaimTypes.Id,admin.AdminId.ToString()),
                        new Claim(JwtClaimTypes.Name,admin.UserName),
                        new Claim(ClaimTypes.Name,admin.UserName),
                        new Claim(ClaimTypes.Role, string.Join(',',roleIds))
                    };

                    //JWT密钥
                    var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(configuration["JwtConfig:key"]));

                    //算法
                    var cred = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);

                    //过期时间
                    DateTime expires = DateTime.UtcNow.AddHours(10);


                    //Payload负载
                    var token = new JwtSecurityToken(
                        issuer: configuration["JwtConfig:Issuer"],
                        audience: configuration["JwtConfig:Audience"],
                        claims: claims,
                        notBefore: DateTime.UtcNow,
                        expires: expires,
                        signingCredentials: cred
                        );

                    var handler = new JwtSecurityTokenHandler();

                    //生成令牌
                    string jwt = handler.WriteToken(token);

                    return new LoginResultDto { Code = Result.Success, Token = jwt, Info = LoginInfo.Success, Message = "登录成功" };
                }
                else
                {
                    return new LoginResultDto { Code = Result.Success, Info = LoginInfo.PasswordError, Message = "密码错误" };
                }
            }            
        }

        #region MyRegion        
        public async Task<PageDto<List<Admin>>> PageDataAsync(int PageIndex = 1,int PageSize = 10)
        {
            var list = repository.Queryable();
            return new PageDto<List<Admin>> {
                Code = Result.Success,
                TotalCount = await list.CountAsync(),
                Data = await list.Skip((PageIndex - 1) * PageSize).Take(PageSize).ToListAsync()
            };
        }

        public async Task<ResultDto<(int, List<Admin>)>> PagerAsync(int PageIndex = 1, int PageSize = 10)
        {
            var list = repository.Queryable();

            var page = await list.Skip((PageIndex - 1) * PageSize).Take(PageSize).ToListAsync();

            return new ResultDto<(int, List<Admin>)>
            {
                Code = Result.Success,
                Data = new(100, page)
            };
        }
        #endregion

        public async Task<ResultDto<Tuple<int, List<ListDto>>>> PageDataTupleAsync(QueryDto query, int PageIndex = 1, int PageSize = 10)
        {
            var list = repository.Queryable().Select(m => new ListDto {
                AdminId = m.AdminId,
                Avatar = m.Avatar,
                CreateName = m.CreateName,
                CreateTime = m.CreateTime,
                Email = m.Email,
                FullName = m.FullName,
                UserName = m.UserName
            });

            //拼接查询条件
            if (!string.IsNullOrEmpty(query.Keywords))
            {
                list = list.Where(m => m.UserName.StartsWith(query.Keywords) || m.FullName.Contains(query.Keywords));
            }

            if(query.StartTime != null)
            {
                list = list.Where(m=>m.CreateTime >= query.StartTime);
            }

            if (query.EndTime != null)
            {
                list = list.Where(m => m.CreateTime <= query.EndTime);
            }
            

            Tuple<int, List<ListDto>> Tuple = new Tuple<int, List<ListDto>>
                (item1: list.Count(), item2: await list.OrderByDescending(m => m.CreateTime).Skip((PageIndex - 1) * PageSize).Take(PageSize).ToListAsync());

            return new ResultDto<Tuple<int, List<ListDto>>> { Code = Result.Success, Data = Tuple };
        }

        public async Task<ResultDto<CreateOrUpdateDto>> FindAsync(int id)
        {
            var admin = await repository.FindAsync(id);
            return new ResultDto<CreateOrUpdateDto> {
             Code = Result.Success,
              Data = new CreateOrUpdateDto {
                  AdminId = admin.AdminId,
                  Avatar = admin.Avatar,
                  Email = admin.Email,
                  FullName = admin.FullName,
                  Remark = admin.Remark,
                  UserName = admin.UserName
              }
            };
        }

        public async Task<ResultDto<bool>> DeleteAsync(int id)
        {
            try
            {
                await repository.DeleteAsync(id);
                return new ResultDto<bool> { Code = Result.Success };
            }
            catch (Exception)
            {
                return new ResultDto<bool> { Code = Result.Failure };
            }            
        }
    }
}
